#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<sstream>
#include<assert.h>
#include<cmath>
#include<vector>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
const int inf=1000000000;
const double pi=acos(-1.0);
#define eps (1e-15)
#define L(x) ((x)<<1)
#define R(x) ((x)<<1|1)
#define clr(x,a) memset(x,a,sizeof(x))
#define see(x)(cerr<<"[line:"<<__LINE__<<" "<<#x<<" "<<x<<endl)
#define se(x) cerr<<x<<" "
#define sz(x) (int)x.size()
#define pb push_back
template<class T>void show(T a, int n){for(int i=0; i<n; ++i) cout<<a[i]<<' '; cout<<endl;}
template<class T>void show(T a, int r, int l){for(int i=0; i<r; ++i)show(a[i],l);cout<<endl;}

inline int to_i(const string& s)
{int n;sscanf(s.c_str(),"%d",&n);return n;}
inline string to_s(int n)
{char buf[32];sprintf(buf,"%d",n);return string(buf);}
inline int rd(){int x;scanf("%d",&x);return x;}

const int inf = 1012345678;
const int maxe = 800010;
const int maxv=  400100;
const int mr=420;
int n,m,S,T;

int first[maxv],next[maxe],C[maxe],M,E[maxe],Ef[maxe];
void initedge()
{
    M=-1;
    memset(first,-1,sizeof(first));
}
void _insert(int a,int b,int c)
{
    M++;
    next[M]=first[a];
    first[a]=M;
    C[M]=c;
    E[M]=b;
    Ef[M]=a;
}
void insert(int i,int j,int c)
{
    _insert(i,j,c);
    _insert(j,i,c);
}

/***********平面图最小割模板*******************/
int g[mr][mr],edge,dot;//dot是点数,g记录方格对应的标号
int h[mr][mr][2];//保存点对应右下角的方格,第一维是方格上面边权，第二维是方格左边边权
void init()//初始话边权,
{//n是方格的行数,m是方格的列数
    int i,j;//n是方格的行数,m是方格的列数
    int tp=1;
    for(i=1; i<=n; i++)
    for(j=1; j<=m; j++)
        g[i][j]=tp++;
    S=tp++;T=tp++;
    //右边和上面都是S
   	for(i=0,j=1; j<=m+1; j++)
   		g[i][j]=S;
   	for(i=0,j=m+1; i<=n; i++)
   		g[i][j]=S;
   	//左边和下面都是T
   	for(i=1,j=0; i<=n+1; i++)
   		g[i][j]=T;
   	for(i=n+1,j=0; j<=m; j++)
   		g[i][j]=T;
    dot=tp+2;//设置点数
}
void buildedge()
{
	int i,j;
	for(i=1; i<=n+1; i++)//n是方格的行数,m是方格的列数
	for(j=1; j<=m+1; j++)
	{
		if(i==n+1 && j==m+1)
			continue;
		insert(g[i][j],g[i-1][j],h[i][j][0]);
		insert(g[i][j],g[i][j-1],h[i][j][1]);
	}
}
/***********平面图最小割模板*******************/

int dis[maxv],in[maxv];
void spfa()
{
    int i,j;
    int s=S,t=T;
    for(i=0; i<dot; i++)
        dis[i]=inf;
    dis[s]=0;
    queue<int>q;
    q.push(s);
    int u,v,e;
    while(!q.empty())
    {
        u=q.front(); q.pop(); in[u]=0;
        for(e=first[u]; e!=-1; e=next[e])
        {
            v=E[e];
            if( dis[u]+C[e]<dis[v])
            {
                dis[v]=dis[u]+C[e];
                if(!in[v])
                {
                q.push(v);
                in[v]=1;
            	}
            }
        }
    }
}

int main()
{
    //freopen("in","r",stdin);
    int i,j,k,t;
    while(scanf("%d%d", &n,&m)!=EOF)
    {
        init();
        initedge();
        int x;
        /***********平面图最小割模板*******************/
        //n是方格的行数,m是方格的列数
        h[n+1][m+1][0]=h[n+1][m+1][1]=inf;//右下角 的方格是不能访问的
		h[0][1][1]= h[1][0][0]=inf;//左上角 的方格也不能访问
       /***********平面图最小割模板*******************/
        for(i=1; i<=n; i++)
        {
        	for(j=1; j<=m; j++)
        		scanf("%d", &h[i][j][0]);
        	for(j=1; j<=m+1; j++)
        		scanf("%d", &h[i][j][1]);
        }
        for(j=1; j<=m; j++)
        		scanf("%d", &h[i][j][0]);
      
        buildedge();
        spfa();
        printf("%d\n",dis[T]);
    }        
}
